package jbase.project.system.core;

import java.util.HashMap;
import java.util.Map;

/**
 * @author LEECHENG
 */
public class Sys {

	private static final int SETVAR = 0x0;
	private static final int GETVAR = 0x1;
	private static final int SETVARS = 0x2;
	private static final int GETVARKEYS = 0x3;
	private static final int REMOVEVAR = 0x4;

	private static final int SETTHREADVAR = 0x5;
	private static final int GETTHREADVAR = 0x6;
	private static final int GETTHREADVARKEYS = 0x7;
	private static final int SETTHREADVARS = 0x8;
	private static final int REMOVETHREADVAR = 0x13;

	private static final int PUSHSTACK = 0x9;
	private static final int POPSTACK = 0xA;
	private static final int GETSTACKDEEP = 0xB;

	private static final int PUSHTHREADSTACK = 0xC;
	private static final int POPTHREADSTACK = 0xD;
	private static final int GETTHREADSTACKDEEP = 0xE;

	private static final int GETSTACKOBJECT = 0xF;
	private static final int GETTHREADSTACKOBJECT = 0x10;

	private static final int IS_STACK_EMPTY = 0x11;
	private static final int IS_THREAD_STACK_EMPTY = 0x12;

	public static java.util.Stack<Object> stack = new java.util.Stack<Object>();
	public static ThreadLocal<java.util.Stack<Object>> threadStack = new ThreadLocal<java.util.Stack<Object>>();
	public static Map<String, Object> vars = new HashMap<String, Object>();
	public static ThreadLocal<Map<String, Object>> threadVars = new ThreadLocal<Map<String, Object>>();

	private static void initThreadVar() {
		if (threadVars.get() == null) {
			threadVars.set(new HashMap<String, Object>());
		}
	}

	private static void initThreadStack() {
		if (threadStack.get() == null) {
			threadStack.set(new java.util.Stack<Object>());
		}
	}

	public static void setVars(Map<String, Object> map) {
		delegate(SETVARS, map);
	}

	public static <T extends Object> T getVar(String name) {
		return getVar(name, null);
	}

	public static <T extends Object> T getVarKeySet() {
		return delegate(GETVARKEYS, null);
	}

	public static <T extends Object> T getVar(String name, Object defaultValue) {
		return delegate(GETVAR, new Object[] { name, defaultValue });
	}

	public static void setVar(String name, Object value) {
		delegate(SETVAR, new Object[] { name, value });
	}

	public static void removeVar(String name) {
		delegate(REMOVEVAR, new Object[] { name });
	}

	public static <T extends Object> T getThreadVar(String name, Object defaultValue) {
		initThreadVar();
		return delegate(GETTHREADVAR, new Object[] { name, defaultValue });
	}

	public static void setThreadVar(String name, Object value) {
		initThreadVar();
		delegate(SETTHREADVAR, new Object[] { name, value });
	}

	public static <T extends Object> T getThreadVarKeySet() {
		initThreadVar();
		return delegate(GETTHREADVARKEYS, null);
	}

	public static void setThreadVars(Map<String, Object> map) {
		initThreadVar();
		delegate(SETTHREADVARS, map);
	}

	public static void removeThreadVar(String name) {
		initThreadVar();
		delegate(REMOVETHREADVAR, name);
	}

	public static void push(Object o) {
		delegate(PUSHSTACK, o);
	}

	public static <T extends Object> T pop() {
		return delegate(POPSTACK, null);
	}

	public static int getStackDeep() {
		return delegate(GETSTACKDEEP, null);
	}

	public static void pushThreadStack(Object o) {
		initThreadStack();
		delegate(PUSHTHREADSTACK, o);
	}

	public static <T extends Object> T popTreadStack() {
		initThreadStack();
		return delegate(POPTHREADSTACK, null);
	}

	public static int getThreadStackDeep() {
		initThreadStack();
		return delegate(GETTHREADSTACKDEEP, null);
	}

	public static <T extends Object> T getStackObject() {
		return delegate(GETSTACKOBJECT, null);
	}

	public static <T extends Object> T getThreadStackObject() {
		return delegate(GETTHREADSTACKOBJECT, null);
	}

	public static Boolean isStackEmpty() {
		return delegate(IS_STACK_EMPTY, null);
	}

	public static Boolean isThreadStackEmpty() {
		return delegate(IS_THREAD_STACK_EMPTY, null);
	}

	@SuppressWarnings("unchecked")
	synchronized private static <T extends Object> T delegate(int operation, Object variants) {
		T returnValue = null;
		synchronized (vars) {
			if (operation == SETVAR) {
				Object[] params = (Object[]) variants;
				String key = (String) params[0];
				Object value = params[1];
				vars.put(key, value);
			} else if (operation == GETVAR) {
				Object[] params = (Object[]) variants;
				String key = (String) params[0];
				Object defVal = params[1];
				if (vars.containsKey(key)) {
					return (T) vars.get(key);
				} else {
					return (T) defVal;
				}
			} else if (operation == GETVARKEYS) {
				return (T) vars.keySet();
			} else if (operation == SETVARS) {
				vars.putAll((Map<String, Object>) variants);
			} else if (operation == REMOVEVAR) {
				vars.remove((String) ((Object[]) variants)[0]);
			}
		}
		synchronized (threadVars) {
			if (operation == SETTHREADVAR) {
				Object[] params = (Object[]) variants;
				String key = (String) params[0];
				Object value = params[1];
				threadVars.get().put(key, value);
			} else if (operation == GETTHREADVAR) {
				Object[] params = (Object[]) variants;
				String key = (String) params[0];
				Object defVal = params[1];
				if (threadVars.get().containsKey(key)) {
					return (T) threadVars.get().get(key);
				} else {
					return (T) defVal;
				}
			} else if (operation == GETTHREADVARKEYS) {
				return (T) threadVars.get().keySet();
			} else if (operation == SETTHREADVARS) {
				threadVars.get().putAll((Map<String, Object>) variants);
			} else if (operation == REMOVETHREADVAR) {
				threadVars.get().remove((String) variants);
			}
		}
		synchronized (stack) {
			if (operation == PUSHSTACK) {
				stack.push(variants);
			} else if (operation == POPSTACK) {
				return (T) stack.pop();
			} else if (operation == GETSTACKDEEP) {
				return (T) new Integer(stack.size());
			} else if (operation == GETSTACKOBJECT) {
				return (T) stack.peek();
			} else if (operation == IS_STACK_EMPTY) {
				return (T) (Object) stack.empty();
			}
		}
		synchronized (threadStack) {
			if (operation == PUSHTHREADSTACK) {
				threadStack.get().push(variants);
			} else if (operation == POPTHREADSTACK) {
				return (T) threadStack.get().pop();
			} else if (operation == GETTHREADSTACKDEEP) {
				return (T) new Integer(threadStack.get().size());
			} else if (operation == GETTHREADSTACKOBJECT) {
				return (T) threadStack.get().peek();
			} else if (operation == IS_THREAD_STACK_EMPTY) {
				return (T) (Object) threadStack.get().empty();
			}
		}
		return (T) returnValue;
	}
}
